package demo.core.runtime.impl;

import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.ServiceEvent;
import org.osgi.framework.ServiceListener;
import org.osgi.framework.ServiceReference;

import demo.core.runtime.extension.AddException;
import demo.core.runtime.extension.ExtendEvent;
import demo.core.runtime.extension.ExtendListener;
import demo.core.runtime.extension.ExtendPoint;
import demo.core.runtime.extension.ExtendRegTable;
import demo.core.runtime.extension.Extension;
import demo.core.runtime.extension.RemoveException;

public class ExtendRegTableImpl implements ExtendRegTable,ServiceListener{
	
	private BundleContext context=null;
	private int index=0;
	
	private Map<Object,Extension> servicesTable=new HashMap<Object,Extension>();
	private Map<String,ExtendConfigImpl> extendConfigMap=new HashMap<String,ExtendConfigImpl>();
	private Set<ExtendListener> listeners=new HashSet<ExtendListener>();

	@Override
	public void addListener(ExtendListener listener) {
		listeners.add(listener);
	}

	@Override
	public void removeListener(ExtendListener listener) {
		listeners.remove(listeners);
	}

	@Override
	public void addExtension(Bundle bundle,ExtendPoint extendPoint, Object extension) throws AddException {
		Extension extensionObj=new Extension(bundle,extension,extendPoint);
		servicesTable.put(extension, extensionObj);
		String extendPointId=extendPoint.getId();
		if(extendConfigMap.containsKey(extendPointId)){
			extendConfigMap.get(extendPointId).addExtension(extensionObj);
		}
		else
			throw new AddException();
	}

	@Override
	public void removeExtension(Object extension) throws RemoveException{
	    Extension extensionObj=servicesTable.remove(extension);
	    if(extensionObj==null)
	    	throw new RemoveException();
	    ExtendPoint extendPoint=extensionObj.getExtendPoint();
	    extendConfigMap.get(extendPoint.getId()).removeExtension(extensionObj);
	}

	@Override
	public void removeExtensions(Set<Object> extensions) throws RemoveException {
		for(Object extension:extensions){
			removeExtension(extension);
		}
		
	}
	
	@Override
	public void serviceChanged(ServiceEvent event) {
		ServiceReference source=event.getServiceReference();
		Object extension=context.getService(source);
		
		Extension extensionObj=servicesTable.get(extension);
		int style=0;
//		System.out.println("DDDDDDDDDDDDDDDDDDD");
		if(event.getType()==ServiceEvent.REGISTERED){
			style=ExtendEvent.REGISTRATION;
		}else if(event.getType()==ServiceEvent.UNREGISTERING){
			style=ExtendEvent.UNREGISTRATION;
		}
		
		ExtendEvent pointEvent=new ExtendEvent(extensionObj,style);
		for(ExtendListener listener:listeners){
			listener.update(pointEvent);
		}
//		System.out.println("Services Registration:"+servicesTable);
//		System.out.println("Extends Registration:"+points);
	}

	public void setContext(BundleContext context) {
		this.context = context;
	}

	@Override
	public Extension[] getExtensions(ExtendPoint extendPoint) {
		ExtendConfigImpl config=extendConfigMap.get(extendPoint);
		if(config!=null)
			return config.getExtensions();
		return null;
	}

	@Override
	public void addExtendPoint(Bundle bundle,String extendPoint) {
		extendConfigMap.put(extendPoint, new ExtendConfigImpl(bundle,extendPoint));
	}

	@Override
	public void removeExtendPoint(String extendPoint) throws RemoveException {
		ExtendConfigImpl config=extendConfigMap.get(extendPoint);
		if(config.getExtensions().length>0)
			throw new RemoveException();
		else
			extendConfigMap.remove(extendPoint);
		
	}

	@Override
	public void removeExtendPoints(Set<String> extendPoints) {
		for(String extendPoint:extendPoints){
			extendConfigMap.remove(extendPoint);
		}
		
	}

	@Override
	public ExtendPoint getExtendPoint(String extendPoint) {
		ExtendConfigImpl config=extendConfigMap.get(extendPoint);
		if(config==null)
			return null;
		else return config.getExtendPoint();
	}
}
